﻿// BarrellShifter.cs
// Provides static methods to perform Arm Barrell shifts in a virtual manner.


using System;

namespace armsim
{
    /// <summary>
    /// Provides statmic methods to perform Arm Barrell Shift
    /// </summary>
    public class BarrelShifter
    {
        /// <summary>
        /// Performs a specified shift type on a uint a given number of times
        /// </summary>
        /// <param name="shiftType">Shift Code indicating the type of shift to perform.</param>
        /// <param name="shifted">The uint to be shifted</param>
        /// <param name="count">The number of shifts to perform</param>
        /// <returns>The number shifted count times</returns>
        public static uint Shift(uint shiftType, uint shifted, uint count)
        {
            switch (shiftType)
            {
                case 0u:
                    return Lsl(shifted, count);

                case 2u:
                    return Asr(shifted, count);

                case 1u:
                    return Lsr(shifted, count);

                case 3u:
                    return Ror(shifted, count);

                default:
                    return shifted;
            }

        }

        /// <summary>
        /// Converts a specified shift operation to its arm assembly representation
        /// </summary>
        /// <param name="shiftType">The kind of shift to convert</param>
        /// <param name="count">the number of times to shift</param>
        /// <param name="isPositive">flag indicating whether the count is positive.</param>
        /// <returns>String containing the assembly</returns>
        public static String ToAssembly(uint shiftType, uint count, bool isPositive = true)
        {


            switch (shiftType)
            {
                case 0u:
                    return String.Format("LSL #{0}", !isPositive ? "-" : "" + count);
                    //return Lsl(shifted, count);

                case 1u:
                    return String.Format("LSR #{0}", !isPositive ? "-" : "" + count);
                    //return Asr(shifted, count);

                case 2u:
                    return String.Format("ASR #{0}", !isPositive ? "-" : "" + count);
                    //return Lsr(shifted, count);

                case 3u:
                    return String.Format("ROR #{0}", !isPositive ? "-" : "" + count);
                    //return Ror(shifted, count);

                default:
                    return String.Format("SHIFT #{0}", !isPositive ? "-" : "" + count);
                    //return shifted;
            }
        }

        /// <summary>
        /// Converts a specified shift type to assembly
        /// </summary>
        /// <param name="shiftType">The ARM Code for the kind of shift to convert</param>
        /// <returns>String containing the assembly</returns>
        public static String ToAssembly(uint shiftType)
        {
            switch (shiftType)
            {
                case 0u:
                    return String.Format("LSL");
                //return Lsl(shifted, count);

                case 1u:
                    return String.Format("ASR");
                //return Asr(shifted, count);

                case 2u:
                    return String.Format("LSR");
                //return Lsr(shifted, count);

                case 3u:
                    return String.Format("ROR");
                //return Ror(shifted, count);

                default:
                    return String.Format("SHIFT");
                //return shifted;
            }
        }

        /// <summary>
        /// Performs a logical shift left
        /// </summary>
        /// <param name="shifted">the uint to be shifted</param>
        /// <param name="count">the number of times to shift</param>
        /// <returns>the shifted uint by count times</returns>
        public static uint Lsl(uint shifted, uint count)
        {
            return shifted << (int)count;
        }

        /// <summary>
        /// Performs a logical shift right
        /// </summary>
        /// <param name="shifted">the uint to be shifted</param>
        /// <param name="count">the number of times to shift</param>
        /// <returns>the shifted uint by count times</returns>
        public static uint Lsr(uint shifted, uint count)
        {
            return shifted >> (int)count;
        }

        /// <summary>
        /// Performs an arithmetic shift right
        /// </summary>
        /// <param name="shifted">the uint to be shifted</param>
        /// <param name="count">the number of times to shift</param>
        /// <returns>the shifted uint by count times</returns>
        public static uint Asr(uint shifted, uint count)
        {

            var tempShifted = (int) shifted;
            var temp = tempShifted >> (int)count;


            return (uint)temp;
        }


        /// <summary>
        /// Performs a Rotate Right
        /// </summary>
        /// <param name="shifted">the uint to be shifted</param>
        /// <param name="count">the number of times to shift</param>
        /// <returns>the shifted uint by count times</returns>
        public static uint Ror(uint shifted, uint count)
        {
            return (shifted >> (int) count) | (shifted << (32 - (int) count));
        }


    }
}
